package com.winning.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.Set;

/**
 * @author Lenovo
 * @title Realm--第一Realm 使用MD5密码进行加密
 * @project shiro-web
 * @package com.winning.shiro.realm
 * @date: 2019-01-18 10:11
 */
public class ShiroRealm extends AuthorizingRealm {

    private static final Logger LOG = LoggerFactory.getLogger(ShiroRealm.class);
    /**
     * 授权方法
     * @param principalCollection 登录用户信息集合
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("ShiroRealm doGetAuthorizationInfo()...");
        LOG.info("class:{},methods:{}",getClass(),"doGetAuthorizationInfo");
        // 1、从principalCollection中获取用户信息
        Object principal = principalCollection.getPrimaryPrincipal();
        // principal是根据Realm中配置的顺序来进行加载的，getPrimaryPrincipal是取第一个
        LOG.info("PrimaryPrincipal:{}",principal);
        LOG.info("PrincipalCollection:{}",principalCollection);
        // 2、利用登录的用户来获取当前登录用户的角色或者权限信息
        Set<String> roles = new HashSet<>();
        roles.add("user");
        if("admin".equals(principal)){
            roles.add("admin");
        }
        // 3、创建SimpleAuthorizationInfo，并设置roles属性
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        // 4、返回SimpleAuthorizationInfo
        return info;
    }

    /**
     * 认证方法
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println(" [First Realm ] doGetAuthenticationInfo ");
        // 1. 获取UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 2.获取用户名
        String username = (String) upToken.getPrincipal();
        // 3.调用数据库方法，从数据库中获取对应的数据库数据
        System.out.println("从数据库中获取username："+username+"所对应的用户信息");
        // 4.若用户不存在，则可以抛出UnknownAccountException
        if("unknown".equals(username)){
            throw new UnknownAccountException("用户不存在");
        }
        // 5.根据用户信息的情况，决定是否需要抛出其他AuthenticationException
        if("xx".equals(username)){
            throw new LockedAccountException("用户被锁定异常");
        }
        // 6.根据用户情况，来构建AuthenticationInfo 对象并返回
        // 通常使用的是：SimpleAuthenticationInfo
        // 参数为：
        // 1）principal 用户名，认证的实体名称
        Object principal = username;
        // 2）credentials: 密码，认证的凭证 数据库获取的密码 会与token中存放的密码进行比对
        Object credentials = "";
        if("admin".equals(username)){
            credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
        }else if ("user".equals(username)){
            credentials = "098d2c478e9c11555ce2823231e02ec1";
        }
        // 3）realmName:当前的realm的名称，使用getName方法即可
        String realmName = getName();
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,realmName);
        // 4）salt 盐值
        ByteSource credentialsSalt = ByteSource.Util.bytes(username);
        info = new SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName);
        return info;
    }

    public static void main(String[] args){
        /* 计算MD5加密1024次密码值 */
        String hashAlgorithmName = "MD5";
        Object credentials = "123456";
        Object salt =  ByteSource.Util.bytes("user");
        int hashIterations = 1024;
        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(result);
    }


}
